// Javascript code
/*
 * author: 小小游 --- allen
 * date: 2015.07.24
 * lastUpdateDate: 2019.10.16
 * description: 基于小小游封装的JS速度版和时间版运动框架
 */
// Tween运动形式
let Tween = {
	linear: function ( t, b, c, d ) {
		return c * t / d + b;
	},
	easeIn: function ( t, b, c, d ) {
		return c * ( t /= d ) * t + b;
	},
	easeOut: function ( t, b, c, d ) {
		return -c * ( t /= d ) * ( t - 2 ) + b;
	},
	easeBoth: function ( t, b, c, d ) {
		if ( ( t /= d / 2 ) < 1 ) {
			return c / 2 * t * t + b;
		}
		return -c / 2 * ( ( --t ) * ( t - 2 ) - 1 ) + b;
	},
	easeInStrong: function ( t, b, c, d ) {
		return c * ( t /= d ) * t * t * t + b;
	},
	easeOutStrong: function ( t, b, c, d ) {
		return -c * ( ( t = t / d - 1 ) * t * t * t - 1 ) + b;
	},
	easeBothStrong: function ( t, b, c, d ) {
		if ( ( t /= d / 2 ) < 1 ) {
			return c / 2 * t * t * t * t + b;
		}
		return -c / 2 * ( ( t -= 2 ) * t * t * t - 2 ) + b;
	},
	elasticIn: function ( t, b, c, d, a, p ) {
		if ( t === 0 ) {
			return b;
		}
		if ( ( t /= d ) == 1 ) {
			return b + c;
		}
		if ( !p ) {
			p = d * 0.3;
		}
		if ( !a || a < Math.abs ( c ) ) {
			a = c;
			var s = p / 4;
		} else {
			var s = p / ( 2 * Math.PI ) * Math.asin ( c / a );
		}
		return -( a * Math.pow ( 2, 10 * ( t -= 1 ) ) * Math.sin ( ( t * d - s ) * ( 2 * Math.PI ) / p ) ) + b;
	},
	elasticOut: function ( t, b, c, d, a, p ) {
		if ( t === 0 ) {
			return b;
		}
		if ( ( t /= d ) == 1 ) {
			return b + c;
		}
		if ( !p ) {
			p = d * 0.3;
		}
		if ( !a || a < Math.abs ( c ) ) {
			a = c;
			var s = p / 4;
		} else {
			var s = p / ( 2 * Math.PI ) * Math.asin ( c / a );
		}
		return a * Math.pow ( 2, -10 * t ) * Math.sin ( ( t * d - s ) * ( 2 * Math.PI ) / p ) + c + b;
	},
	elasticBoth: function ( t, b, c, d, a, p ) {
		if ( t === 0 ) {
			return b;
		}
		if ( ( t /= d / 2 ) == 2 ) {
			return b + c;
		}
		if ( !p ) {
			p = d * ( 0.3 * 1.5 );
		}
		if ( !a || a < Math.abs ( c ) ) {
			a = c;
			var s = p / 4;
		} else {
			var s = p / ( 2 * Math.PI ) * Math.asin ( c / a );
		}
		if ( t < 1 ) {
			return -0.5 * ( a * Math.pow ( 2, 10 * ( t -= 1 ) ) * Math.sin ( ( t * d - s ) * ( 2 * Math.PI ) / p ) ) + b;
		}
		return a * Math.pow ( 2, -10 * ( t -= 1 ) ) * Math.sin ( (t * d - s ) * ( 2 * Math.PI ) / p ) * 0.5 + c + b;
	},
	backIn: function ( t, b, c, d, s ) {
		if ( typeof s == 'undefined' ) {
			s = 1.70158;
		}
		return c * ( t /= d ) * t * ( ( s + 1 ) * t - s ) + b;
	},
	backOut: function ( t, b, c, d, s ) {
		if ( typeof s == 'undefined' ) {
			s = 3.70158;
		}
		return c * ( ( t = t / d - 1 ) * t * ( ( s + 1 ) * t + s ) + 1 ) + b;
	},
	backBoth: function ( t, b, c, d, s ) {
		if ( typeof s == 'undefined' ) {
			s = 1.70158;
		}
		if ( ( t /= d / 2 ) < 1 ) {
			return c / 2 * ( t * t * ( ( ( s *= ( 1.525 ) ) + 1 ) * t - s ) ) + b;
		}
		return c / 2 * ( ( t -= 2 ) * t * ( ( ( s *= ( 1.525 ) ) + 1 ) * t + s ) + 2 ) + b;
	},
	bounceIn: function ( t, b, c, d ) {
		return c - Tween['bounceOut']( d - t, 0, c, d ) + b;
	},
	bounceOut: function ( t, b, c, d ) {
		if ( ( t /= d ) < ( 1 / 2.75 ) ) {
			return c * ( 7.5625 * t * t ) + b;
		} else if ( t < ( 2 / 2.75 ) ) {
			return c * ( 7.5625 * ( t -= ( 1.5 / 2.75 ) ) * t + 0.75 ) + b;
		} else if ( t < ( 2.5 / 2.75 ) ) {
			return c * ( 7.5625 * ( t -= ( 2.25 / 2.75 ) ) * t + 0.9375 ) + b;
		}
		return c * ( 7.5625 * ( t -= ( 2.625 / 2.75 ) ) * t + 0.984375 ) + b;
	},
	bounceBoth: function ( t, b, c, d ) {
		if ( t < d / 2 ) {
			return Tween['bounceIn']( t * 2, 0, c, d ) * 0.5 + b;
		}
		return Tween['bounceOut']( t * 2 - d, 0, c, d ) * 0.5 + c * 0.5 + b;
	}
};

// 凯游网时间版运动
function kaiyouTweenStartMove ( obj, oTarget, iTime, iType, fnEnd, fnDuring ) {
	var fn = Tween[iType];
	var t = 0;
	var b = {};
	var c = {};
	var d = iTime / 24;
	var MT = {};
	var sAttr = "";
	clearInterval( obj.timer );
	for ( sAttr in oTarget ) {
		b[sAttr] = css( obj, sAttr );
		c[sAttr] = oTarget[sAttr] - b[sAttr];
		MT[sAttr] = 0;
	}
	if ( iTime < 30 ) {
		for ( sAttr in oTarget ) {
			css ( obj, sAttr, oTarget[sAttr] );
		}
	} else {
		obj.timer = setInterval ( function () {
			if ( t < d ) {
				t++;
				for ( sAttr in oTarget ) {
					MT[sAttr] = fn ( t, b[sAttr], c[sAttr], d );
					css ( obj, sAttr, fn ( t, b[sAttr], c[sAttr], d ) );
				}
			} else {
				for ( sAttr in oTarget ) {
					css ( obj, sAttr, oTarget[sAttr] );
				}
				clearInterval ( obj.timer );
				if ( fnEnd ) {
					fnEnd.call ( obj );
				}
			}
			if ( fnDuring ) {
				fnDuring.call ( obj, b, MT, t );
			}
		}, 24 );
	}
}

// --------------------------------------------------------------------------- //

// 定义速度版的运动变量
let KAIYOU_MOVE_TYPE = {
	// 缓冲运动
	BUFFER: 1,
	// 弹性运动
	FLEX: 2,
	// 加速运动
	FAST: 3,
	// 减速运动
	SLOW: 4,
	// 匀速运动
	NORMAL: 5
};

// 速度版的缓冲运动和弹性运动形式，其它运动形式可以自己添加
function kaiyouStartMove ( obj, oTarget, iType, fnCallBack, fnDuring ) {
	let fnMove = null;
	
	if ( obj.timer ) {
		clearInterval ( obj.timer );
	}
	
	switch ( iType ) {
		case KAIYOU_MOVE_TYPE.BUFFER:
			fnMove = kaiyouDoMoveBuffer;
			break;
		case KAIYOU_MOVE_TYPE.FLEX:
			fnMove = kaiyouDoMoveFlex;
			break;
	}
	
	obj.timer = setInterval ( function () {
		fnMove ( obj, oTarget, fnCallBack, fnDuring );
		var now = ( new Date () ).getTime ();
		obj.lastMove = now;
	}, 30 );
	
	if ( !obj.lastMove ) {
		obj.lastMove = 0;
	}
	
	var now = ( new Date () ).getTime ();
	
	if ( now - obj.lastMove > 30 ) {
		fnMove ( obj, oTarget, fnCallBack, fnDuring );
		var now = ( new Date () ).getTime ();
		obj.lastMove = now;
	}
}

// 速度版缓冲运动形式
function kaiyouDoMoveBuffer ( obj, oTarget, fnCallBack, fnDuring ) {
	var bStop = true;
	var attr = '';
	var speed = 0;
	var cur = 0;
	for ( attr in oTarget ) {
		oTarget[attr] = parseInt ( oTarget[attr] );
		cur = css ( obj, attr );
		if ( oTarget[attr] != cur ) {
			bStop = false;
			speed = ( oTarget[attr] - cur ) / 5;
			speed = speed > 0 ? Math.ceil ( speed ) : Math.floor ( speed );
			css ( obj, attr, cur + speed );
		}
	}
	
	if ( fnDuring ) fnDuring.call ( obj );
	
	if ( bStop ) {
		clearInterval ( obj.timer );
		obj.timer = null;
		if ( fnCallBack ) fnCallBack.call ( obj );
	}
}

// 速度版弹性运动形式
function kaiyouDoMoveFlex ( obj, oTarget, fnCallBack, fnDuring ) {
	var bStop = true;
	var attr = '';
	var speed = 0;
	var cur = 0;
	for ( attr in oTarget ) {
		if ( !obj.oSpeed ) obj.oSpeed = {};
		if ( !obj.oSpeed[attr] ) obj.oSpeed[attr] = 0;
		cur = css ( obj, attr );
		if ( Math.abs ( oTarget[attr] - cur ) >= 1 || Math.abs ( obj.oSpeed[attr] ) >= 1 ) {
			bStop = false;
			obj.oSpeed[attr] += ( oTarget[attr] - cur ) / 5;
			obj.oSpeed[attr] *= 0.75;
			css ( obj, attr, cur + obj.oSpeed[attr] );
		}
	}
	
	if ( fnDuring ) fnDuring.call ( obj );
	if ( bStop ) {
		clearInterval ( obj.timer );
		obj.timer = null;
		if ( fnCallBack ) fnCallBack.call ( obj );
	}
}

// 速度版停止运动，清除定时器
function stopMove ( obj ) {
	clearInterval ( obj.timer );
}

// --------------------------------------------------------------------------- //
// 用来特殊处理right等属性的缓冲和弹性运动形式
/**
 * 多值同时运动的带缓冲形式的完美运动框架 start
*/
function perfectKaiyouStartMove ( obj, json, fn ) {
	clearInterval ( obj.timer );
	obj.timer = setInterval ( function () {
		// 假设运动的过程中所有的值都到了，表示状态为true
		let bStop = true; 
		for ( let attr in json ) {
			// 存储目标值
			let iTarget = json[attr];
			
			// 取当前值
			let iCur = 0;
			
			if ( attr == 'opacity' ) {
				iCur = Math.round ( parseFloat ( getStyle ( obj, attr ) ) * 100 );
			} else {
				iCur = parseInt ( getStyle ( obj,attr ) );
			}
			
			// 计算速度
			let iSpeed = ( iTarget - iCur ) / 4;
			iSpeed = iSpeed > 0 ? Math.ceil ( iSpeed ) : Math.floor ( iSpeed );
			
			// 检测停止
			// 如果有一个值没到就把bStop的值改成false
			if ( iCur != iTarget ) {
				bStop = false;
			}
			
			iCur += iSpeed;
			if ( attr == 'opacity' ) {
				obj.style.filter = 'alpha( opacity:'+ iCur +' ) ';
				obj.style.opacity = iCur / 100;
			} else {
				obj.style[attr] = iCur + 'px';
			}
		}
		
		// 如果这时候bStop的值都还是true的话，表示全部值都到了，就关闭定时器
		if ( bStop ) {
			clearInterval ( obj.timer );
			obj.timer = null;
			fn && fn.call ( obj );
		}
	}, 30 );
}
/**
 * 多值同时运动的带缓冲形式的完美运动框架 end
*/
